package com.qd.panda.gas.station.shell.last;

import cn.hutool.core.math.Money;
import com.cdqidi.exception.ApiException;
import com.cdqidi.util.JacksonUtil;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.qd.common.panda.constant.PandaConstant;
import com.qd.common.panda.domain.entity.carpark.calculate.CalculatePriceDTO;
import com.qd.common.panda.domain.entity.carpark.calculate.CalculatePriceDetailDTO;
import com.qd.common.panda.domain.enums.GasStationCompanyNameEnum;
import com.qd.common.panda.domain.enums.PreferentialCategoryEnum;
import com.qd.common.sys.domain.entity.log.SendLogDTO;
import com.qd.panda.gas.station.req.ComputeReqDTO;
import com.qd.panda.gas.station.shell.config.ShellConfig;
import com.qd.panda.gas.station.shell.req.last.ShellCalculateReqDTO;
import com.qd.panda.model.CarParkGasStation;
import com.qd.panda.model.CarParkGasStationPrice;
import com.qd.panda.service.park.CarParkGasStationPriceService;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpMethod;
import org.springframework.stereotype.Component;
import org.springframework.web.client.RestTemplate;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;

/**
 * 壳牌民营，逻辑和壳牌普通完全一致
 * 只是价格计算有区别
 *
 * @author sjk
 * @create 2022-10-08 15:00
 * @since 1.0.0
 */
@Component
@Slf4j
@Qualifier("ShellOtherHttpServiceImpl")
public class LastShellOtherHttpServiceImpl extends LastShellHttpServiceImpl {

    /**
     * 计算价格
     */
    private static final String CALCULATE_URL = "/n/a/open/oil/pay/calculate";
    @Resource
    private ShellConfig shellConfig;

    private final CarParkGasStationPriceService carParkGasStationPriceService;
    private final RestTemplate restTemplate;
    private final ObjectMapper objectMapper;

    public LastShellOtherHttpServiceImpl(RestTemplate restTemplate, ObjectMapper objectMapper, CarParkGasStationPriceService carParkGasStationPriceService) {
        super(restTemplate, objectMapper);
        this.carParkGasStationPriceService = carParkGasStationPriceService;
        this.restTemplate = restTemplate;
        this.objectMapper = objectMapper;
    }

    @Override
    public String stationCompanyId() {
        return GasStationCompanyNameEnum.EXTEND_SHELL_OTHER.getCode();
    }

    @SneakyThrows
    @Override
    public CalculatePriceDTO compute(ComputeReqDTO computeReqDTO) {
        List<CarParkGasStationPrice> list = carParkGasStationPriceService.getGasStationPriceListByParkId(computeReqDTO.getParkId());
        if (list.isEmpty()) {
            throw new ApiException("加油站价格为空");
        }
        Map<String, CarParkGasStationPrice> priceMap = new HashMap<>();
        for (CarParkGasStationPrice carParkGasStationPrice : list) {
            String nozzleNumbersStr = carParkGasStationPrice.getNozzleNumbers();
            String[] nozzleNumbers = nozzleNumbersStr.split(",");
            for (String nozzleNumber : nozzleNumbers) {
                priceMap.put(nozzleNumber, carParkGasStationPrice);
            }
        }

        CarParkGasStationPrice carParkGasStationPrice = Optional.ofNullable(priceMap.get(computeReqDTO.getNozzleNumber())).orElseThrow(() -> new ApiException("加油站扩展信息不存在"));
        CarParkGasStation carParkGasStation = Optional.ofNullable(carParkGasStationService.getById(computeReqDTO.getParkId())).orElseThrow(() -> new ApiException("加油站不存在"));


        BigDecimal amount = calculate(computeReqDTO, carParkGasStationPrice);


        CalculatePriceDTO calculatePrice = getCalculatePriceDTO(computeReqDTO, amount);
        buildDiscount(calculatePrice);

        Optional.ofNullable(calculatePrice.getCalculatePrice()).ifPresent(calculatePriceDTO -> calculatePrice.setCalculatePriceDisplay(calculatePrice.getCalculatePrice().toPlainString()));
        Optional.ofNullable(calculatePrice.getPrice()).ifPresent(calculatePriceDTO -> calculatePrice.setPriceDisplay(calculatePrice.getPrice().toPlainString()));
        Optional.ofNullable(calculatePrice.getDiscountAmount()).ifPresent(calculatePriceDTO -> calculatePrice.setDiscountAmountDisplay(calculatePrice.getDiscountAmount().toPlainString()));

        log.info("新新调用接口查询，油站所属公司: {},原价: {},优惠价: {},优惠金额: {}", carParkGasStation.getGasStationCompanyName(), calculatePrice.getPriceDisplay(), calculatePrice.getCalculatePriceDisplay(), calculatePrice.getDiscountAmount());
        return calculatePrice;
    }

    @SneakyThrows
    private BigDecimal calculate(ComputeReqDTO computeReqDTO, CarParkGasStationPrice carParkGasStationPrice) {
        ShellCalculateReqDTO shellCalculateReqDTO = new ShellCalculateReqDTO();
        shellCalculateReqDTO.setStationId(Integer.parseInt(computeReqDTO.getStationId()))
                .setTotalAmount(computeReqDTO.getTotalAmount())
                .setOctaneNumber(carParkGasStationPrice.getOctaneNumber());

        Map<String, Object> param = objectMapper.convertValue(shellCalculateReqDTO, new TypeReference<>() {
        });
        String url = shellConfig.getUrl() + CALCULATE_URL;
        buildSign(param, null);
        shellCalculateReqDTO.setPartnerId(param.get("partnerId").toString());
        shellCalculateReqDTO.setTimestamp(param.get("timestamp").toString());
        shellCalculateReqDTO.setSign(param.get("sign").toString());
        String reqJson = JacksonUtil.getObjectMapper().writeValueAsString(shellCalculateReqDTO);
        log.info("新新壳牌民营和高速,调用接口算费,url: {},参数: {}", url, reqJson);
        final SendLogDTO sendLog = computeReqDTO.getSendLogDTO();
        HttpEntity<Object> httpEntity = new HttpEntity<>(shellCalculateReqDTO);
        JsonNode responseJson = build(() -> restTemplate.exchange(url, HttpMethod.POST, httpEntity, String.class, shellConfig.getNormalKey()));
        if (null != sendLog) {
            sendLog.setUrl(url);
            sendLog.setReqMethod(HttpMethod.POST.name());
            sendLog.setReqParam(reqJson);
            sendLog.setResponseMsg(responseJson.toString());
        }
        return responseJson.get("data").decimalValue();
    }


    private CalculatePriceDTO getCalculatePriceDTO(ComputeReqDTO computeReqDTO, BigDecimal amount) {
        BigDecimal totalAmountBigDecimal = new BigDecimal(String.valueOf(computeReqDTO.getTotalAmount()));
        //计算加油量
        BigDecimal oilVolume = totalAmountBigDecimal.divide(totalAmountBigDecimal, 2, RoundingMode.HALF_UP);
        //优惠金额
        BigDecimal multiply = totalAmountBigDecimal.subtract(amount);
        log.info("优惠金额: {}", multiply);
        CalculatePriceDTO calculatePrice = new CalculatePriceDTO();
        //向上取整
        calculatePrice.setCalculatePrice(amount);
        calculatePrice.setPrice(computeReqDTO.getTotalAmount());
        calculatePrice.setDiscountAmount(multiply);
        calculatePrice.setOilVolume(oilVolume);
        return calculatePrice;

    }

//    private CalculatePriceDTO getCalculatePriceDTO(ComputeReqDTO computeReqDTO, CarParkGasStationPrice carParkGasStationPrice) {
//        BigDecimal totalAmountBigDecimal = new BigDecimal(String.valueOf(computeReqDTO.getTotalAmount()));
//        //计算加油量
//        BigDecimal oilVolume = totalAmountBigDecimal.divide(carParkGasStationPrice.getPrice(), 2, RoundingMode.HALF_UP);
//        log.info("加油量: {}", oilVolume);
//        //每升优惠金额
//        BigDecimal subtract = carParkGasStationPrice.getPrice().subtract(carParkGasStationPrice.getCustomerPrice());
//        log.info("每升优惠金额: {}", subtract);
//        //优惠金额
//        BigDecimal multiply = oilVolume.multiply(subtract).setScale(2, RoundingMode.HALF_UP);
//        log.info("优惠金额: {}", multiply);
//        return getCalculatePriceDTO(computeReqDTO, multiply);
//    }

//    private CalculatePriceDTO getCalculatePriceDTO(ComputeReqDTO computeReqDTO, BigDecimal multiply) {
//        CalculatePriceDTO calculatePrice = new CalculatePriceDTO();
//        //向上取整
//        calculatePrice.setCalculatePrice((computeReqDTO.getTotalAmount().subtract(multiply)).setScale(2, RoundingMode.UP));
//        calculatePrice.setPrice(computeReqDTO.getTotalAmount());
//        calculatePrice.setDiscountAmount(multiply);
//        return calculatePrice;
//    }

    private void buildDiscount(CalculatePriceDTO calculatePrice) {
        Money allDiscountAmount = new Money();
        //不为空且值大于0
        if (null != calculatePrice.getCouponAmount() && calculatePrice.getCouponAmount().compareTo(BigDecimal.ZERO) > 0) {
            allDiscountAmount = allDiscountAmount.add(new Money(calculatePrice.getCouponAmount()));
            calculatePrice.setRefuelingAmount(calculatePrice.getCalculatePrice());
            calculatePrice.addCalculatePriceDetailDTO(new CalculatePriceDetailDTO()
                    .setCalculatePrice(calculatePrice.getCalculatePrice())
                    .setPrice(calculatePrice.getPrice())
                    .setDiscountAmount(calculatePrice.getCouponAmount())
                    .setPlatform(PandaConstant.PLATFORM_EXTEND_SHELL)
                    .setServiceFee(calculatePrice.getServiceFee())
                    .setPreferentialCategory(PreferentialCategoryEnum.PREFERENTIAL_3.getCode()));
        }
        //不为空且值大于0
        if (null != calculatePrice.getDiscountAmount() && calculatePrice.getDiscountAmount().compareTo(BigDecimal.ZERO) > 0) {
            allDiscountAmount = allDiscountAmount.add(new Money(calculatePrice.getDiscountAmount()));
            calculatePrice.setRefuelingAmount(calculatePrice.getCalculatePrice());
            calculatePrice.addCalculatePriceDetailDTO(new CalculatePriceDetailDTO()
                    .setCalculatePrice(calculatePrice.getCalculatePrice())
                    .setPrice(calculatePrice.getPrice())
                    .setDiscountAmount(calculatePrice.getDiscountAmount())
                    .setPlatform(PandaConstant.PLATFORM_EXTEND_SHELL)
                    .setServiceFee(calculatePrice.getServiceFee())
                    .setPreferentialCategory(PreferentialCategoryEnum.PREFERENTIAL_1.getCode()));
        }
        calculatePrice.setDiscountAmount(allDiscountAmount.getAmount());
    }
}